I. Preliminaries

Loading libraries

library("tidyverse")
library("tibble")
library("msigdbr")
library("ggplot2")
library("TCGAbiolinks")
library("RNAseqQC")
library("DESeq2")
library("ensembldb")
library("purrr")
library("magrittr")
library("vsn")
library("matrixStats")
library("dplyr")
library("grex")

Constants

DATA_DIR <- "../data/public/GTEx/"

II. Loading the GTEx annotations

sample.df <- read.delim(paste0(DATA_DIR, "GTEx_Analysis_v8_Annotations_SampleAttributesDS.txt"), as.is = TRUE, header = TRUE, row.names = 1)
subject.df <- read.delim(paste0(DATA_DIR, "GTEx_Analysis_v8_Annotations_SubjectPhenotypesDS.txt"), as.is = TRUE, header = TRUE, row.names = 1)

The DTHHRDY column refers to the 4-point Hardy scale: https://www.ncbi.nlm.nih.gov/projects/gap/cgi-bin/variable.cgi?study_id=phs000424.v4.p1&phv=169092

Refer to the metadata files here for more information: https://gtexportal.org/home/downloads/adult-gtex/metadata

subject.df

Refer to the metadata files here for more information: https://gtexportal.org/home/downloads/adult-gtex/metadata

sample.df

Extract entries that pertain to transcriptomic (RNA) data.

rnaseq.sample.df <- sample.df[sample.df["SMAFRZE"] == "RNASEQ", ]
rnaseq.sample.df

III. Filtering colon samples

The SMTSD column refers to the tissue type (i.e., the area from which the sample was taken).

as.matrix(sort(table(rnaseq.sample.df["SMTSD"]), decreasing = TRUE))
                                          [,1]
Muscle - Skeletal                          803
Whole Blood                                755
Skin - Sun Exposed (Lower leg)             701
Adipose - Subcutaneous                     663
Artery - Tibial                            663
Thyroid                                    653
Nerve - Tibial                             619
Skin - Not Sun Exposed (Suprapubic)        604
Lung                                       578
Esophagus - Mucosa                         555
Adipose - Visceral (Omentum)               541
Esophagus - Muscularis                     515
Cells - Cultured fibroblasts               504
Breast - Mammary Tissue                    459
Artery - Aorta                             432
Heart - Left Ventricle                     432
Heart - Atrial Appendage                   429
Colon - Transverse                         406
Esophagus - Gastroesophageal Junction      375
Colon - Sigmoid                            373
Testis                                     361
Stomach                                    359
Pancreas                                   328
Pituitary                                  283
Adrenal Gland                              258
Brain - Cortex                             255
Brain - Caudate (basal ganglia)            246
Brain - Nucleus accumbens (basal ganglia)  246
Prostate                                   245
Brain - Cerebellum                         241
Spleen                                     241
Artery - Coronary                          240
Liver                                      226
Brain - Cerebellar Hemisphere              215
Brain - Frontal Cortex (BA9)               209
Brain - Putamen (basal ganglia)            205
Brain - Hypothalamus                       202
Brain - Hippocampus                        197
Small Intestine - Terminal Ileum           187
Ovary                                      180
Brain - Anterior cingulate cortex (BA24)   176
Cells - EBV-transformed lymphocytes        174
Minor Salivary Gland                       162
Brain - Spinal cord (cervical c-1)         159
Vagina                                     156
Brain - Amygdala                           152
Uterus                                     142
Brain - Substantia nigra                   139
Kidney - Cortex                             85
Bladder                                     21
Cervix - Endocervix                         10
Cervix - Ectocervix                          9
Fallopian Tube                               9
Kidney - Medulla                             4

We are only interested in those from the colorectal area.

colon.sample.df <- rnaseq.sample.df %>% dplyr::filter(SMTSD == "Colon - Sigmoid")
colon.sample.df

IV. Loading TPM data from GTEx

GTEx_Analysis_2017-06-05_v8_RNASeQCv1.1.9_gene_tpm.gct contains the gene TPMs.

tpm.df <- read.delim(paste0(DATA_DIR, "GTEx_Analysis_2017-06-05_v8_RNASeQCv1.1.9_gene_tpm.gct"),
  as.is = T, row.names = 1, check.names = FALSE, skip = 2
)
gene.names.df <- tpm.df[, "Description", drop = FALSE]
tpm.df <- tpm.df[, !(names(tpm.df) %in% c("Description"))]
{
  cat(paste("Number of genes in table: ", dim(tpm.df)[1]))
}
Number of genes in table:  56200

Perform some data preprocessing.

# Remove version number: https://www.rdocumentation.org/packages/grex/versions/1.9/topics/cleanid
tpm.df$ensembl <- cleanid(rownames(tpm.df))
head(tpm.df$ensembl)
[1] "ENSG00000223972" "ENSG00000227232" "ENSG00000278267" "ENSG00000243485" "ENSG00000237613" "ENSG00000268020"

FADD is one of the key genes involved in necroptosis.

# Create a named vector to map names to IDs
name_to_id <- setNames(rownames(gene.names.df), gene.names.df$Description)

# Create a named vector to map IDs to names
id_to_name <- setNames(gene.names.df$Description, rownames(gene.names.df))

# To retrieve the ID for 'FADD'
print(name_to_id[["FADD"]])
[1] "ENSG00000168040.4"
print(id_to_name[["ENSG00000168040.4"]])
[1] "FADD"

V. Loading RCD gene sets

Necroptosis

We obtain the gene set from the Human MSigDB Collections:

CAVEAT! GOBP_NECROPTOTIC_SIGNALING_PATHWAY contains only 8 genes.

necroptosis.genes <- msigdbr(species = "human", category = "C5", subcategory = "GO:BP") %>%
  dplyr::filter(gs_name == "GOBP_NECROPTOTIC_SIGNALING_PATHWAY")
necroptosis.genes

Ferroptosis

We obtain the gene set from the Human MSigDB Collections:

Note that there is another ferroptosis gene set: GOBP_FERROPTOSIS.
However, it contains only 10 genes (for comparison, WP_FERROPTOSIS contains 64 genes).

ferroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:WIKIPATHWAYS") %>%
  dplyr::filter(gs_name == "WP_FERROPTOSIS")
ferroptosis.genes

Pyroptosis

We obtain the gene set from the Human MSigDB Collections:

REACTOME_PYROPTOSIS contains 27 genes.

pyroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:REACTOME") %>%
  dplyr::filter(gs_name == "REACTOME_PYROPTOSIS")
pyroptosis.genes

VI. Exploratory Data Analysis

Select only the tissue samples (columns) from the colorectal area.

tpm.colon.df <- tpm.df %>% dplyr::select(c(ensembl, rownames(colon.sample.df)))
tpm.colon.df

Necroptosis

Get the TPM for the genes in the necroptosis gene set.

tpm.colon.necro.df <- tpm.colon.df %>% dplyr::filter(ensembl %in% necroptosis.genes$ensembl_gene)
tpm.colon.necro.df2 <- left_join(tpm.colon.necro.df, necroptosis.genes %>% dplyr::select(ensembl_gene, gene_symbol), by = c("ensembl" = "ensembl_gene"))
tpm.colon.necro.df$gene_symbol <- tpm.colon.necro.df2$gene_symbol
tpm.colon.necro.df

Compute the median TPM per gene.

gene.expressions.necro <- data.frame(
  row.names = tpm.colon.necro.df$gene_symbol,
  tissue = "Colon",
  tpm = matrixStats::rowMedians(as.matrix(tpm.colon.necro.df %>% dplyr::select(-c("ensembl", "gene_symbol"))))
)
gene.expressions.necro

Plot the gene expression.

ggplot(gene.expressions.necro, aes(y = tissue, x = rownames(gene.expressions.necro), fill = tpm)) +
  geom_tile() +
  scale_fill_gradient(low = "white", high = "red") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 9, hjust = 1)
  ) +
  labs(
    title = "Expression of necroptosis-related genes in GTEx colon tissues",
    x = "Gene",
    y = "Area",
    fill = "TPM"
  ) +
  geom_text(aes(label = tpm), vjust = 1)

Quick validation: RIPK1 and necroptosis - https://www.nature.com/articles/s12276-022-00847-4

Ferroptosis

Get the TPM for the genes in the ferroptosis gene set.

tpm.colon.ferro.df <- tpm.colon.df %>% dplyr::filter(ensembl %in% ferroptosis.genes$ensembl_gene)
tpm.colon.ferro.df2 <- left_join(tpm.colon.ferro.df, ferroptosis.genes %>% dplyr::select(ensembl_gene, gene_symbol), by = c("ensembl" = "ensembl_gene"))
tpm.colon.ferro.df$gene_symbol <- tpm.colon.ferro.df2$gene_symbol
tpm.colon.ferro.df

Compute the median TPM per gene.

gene.expressions.ferro <- data.frame(
  row.names = tpm.colon.ferro.df$gene_symbol,
  tissue = "Colon",
  tpm = matrixStats::rowMedians(as.matrix(tpm.colon.ferro.df %>% dplyr::select(-c("ensembl", "gene_symbol"))))
)
gene.expressions.ferro

Plot the gene expression.

ggplot(gene.expressions.ferro, aes(y = tissue, x = rownames(gene.expressions.ferro), fill = tpm)) +
  geom_tile() +
  scale_fill_gradient(low = "white", high = "red") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 7, angle = 90, hjust = 1)
  ) +
  labs(
    title = "Expression of ferroptosis-related genes in GTEx colon tissues",
    x = "Gene",
    y = "Area",
    fill = "TPM"
  )

Quick validation: FTH1 and ferroptosis - https://www.nature.com/articles/s41420-022-00902-z

Pyroptosis

Get the TPM for the genes in the pyroptosis gene set.

tpm.colon.pyro.df <- tpm.colon.df %>% dplyr::filter(ensembl %in% pyroptosis.genes$ensembl_gene)
tpm.colon.pyro.df2 <- left_join(tpm.colon.pyro.df, pyroptosis.genes %>% dplyr::select(ensembl_gene, gene_symbol), by = c("ensembl" = "ensembl_gene"))
tpm.colon.pyro.df$gene_symbol <- tpm.colon.pyro.df2$gene_symbol
tpm.colon.pyro.df

Compute the median TPM per gene.

gene.expressions.pyro <- data.frame(
  row.names = tpm.colon.pyro.df$gene_symbol,
  tissue = "Colon",
  tpm = matrixStats::rowMedians(as.matrix(tpm.colon.pyro.df %>% dplyr::select(-c("ensembl", "gene_symbol"))))
)
gene.expressions.pyro

Plot the gene expression.

ggplot(gene.expressions.pyro, aes(y = tissue, x = rownames(gene.expressions.pyro), fill = tpm)) +
  geom_tile() +
  scale_fill_gradient(low = "white", high = "red") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 7, angle = 90, hjust = 1)
  ) +
  labs(
    title = "Expression of pyroptosis-related genes in GTEx colon tissues",
    x = "Gene",
    y = "Area",
    fill = "TPM"
  )

Quick validation: CHMP4B and pyroptosis - https://pubmed.ncbi.nlm.nih.gov/38823000/


  1. De La Salle University, Manila, Philippines, ↩︎

  2. De La Salle University, Manila, Philippines, ↩︎

  3. De La Salle University, Manila, Philippines, ↩︎

LS0tDQp0aXRsZTogIkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMiDQphdXRob3I6IA0KICAtIEtpbSBXaWxsaWFtZSBMZWVeW0RlIExhIFNhbGxlIFVuaXZlcnNpdHksIE1hbmlsYSwgUGhpbGlwcGluZXMsIGtpbV9sZWVqcmFAZGxzdS5lZHUucGhdDQogIC0gTWFyayBFZHdhcmQgTS4gR29uemFsZXNeW0RlIExhIFNhbGxlIFVuaXZlcnNpdHksIE1hbmlsYSwgUGhpbGlwcGluZXMsIGdvbnphbGVzLm1hcmtlZHdhcmRAZ21haWwuY29tXQ0KICAtIERyLiBBbmlzaCBNLlMuIFNocmVzdGhhXltEZSBMYSBTYWxsZSBVbml2ZXJzaXR5LCBNYW5pbGEsIFBoaWxpcHBpbmVzLCBhbmlzaC5zaHJlc3RoYUBkbHN1LmVkdS5waF0NCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIEkuIFByZWxpbWluYXJpZXMNCg0KIyMjIExvYWRpbmcgbGlicmFyaWVzDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSgidGlkeXZlcnNlIikNCmxpYnJhcnkoInRpYmJsZSIpDQpsaWJyYXJ5KCJtc2lnZGJyIikNCmxpYnJhcnkoImdncGxvdDIiKQ0KbGlicmFyeSgiVENHQWJpb2xpbmtzIikNCmxpYnJhcnkoIlJOQXNlcVFDIikNCmxpYnJhcnkoIkRFU2VxMiIpDQpsaWJyYXJ5KCJlbnNlbWJsZGIiKQ0KbGlicmFyeSgicHVycnIiKQ0KbGlicmFyeSgibWFncml0dHIiKQ0KbGlicmFyeSgidnNuIikNCmxpYnJhcnkoIm1hdHJpeFN0YXRzIikNCmxpYnJhcnkoImRwbHlyIikNCmxpYnJhcnkoImdyZXgiKQ0KYGBgDQoNCiMjIyBDb25zdGFudHMNCmBgYHtyfQ0KREFUQV9ESVIgPC0gIi4uL2RhdGEvcHVibGljL0dURXgvIg0KYGBgDQoNCiMjIElJLiBMb2FkaW5nIHRoZSBHVEV4IGFubm90YXRpb25zDQoNCi0gYEdURXhfQW5hbHlzaXNfdjhfQW5ub3RhdGlvbnNfU2FtcGxlQXR0cmlidXRlc0RTLnR4dGAgLSBBIGRlLWlkZW50aWZpZWQsIG9wZW4gYWNjZXNzIHZlcnNpb24gb2YgdGhlIHNhbXBsZSBhbm5vdGF0aW9ucyBhdmFpbGFibGUgaW4gZGJHYVAgKGRhdGFiYXNlIG9mIGdlbm90eXBlcyBhbmQgcGhlbm90eXBlcykNCi0gYEdURXhfQW5hbHlzaXNfdjhfQW5ub3RhdGlvbnNfU3ViamVjdFBoZW5vdHlwZXNEUy50eHRgIC0gQSBkZS1pZGVudGlmaWVkLCBvcGVuIGFjY2VzcyB2ZXJzaW9uIG9mIHRoZSBzdWJqZWN0IHBoZW5vdHlwZXMgYXZhaWxhYmxlIGluIGRiR2FQLgkNCg0KYGBge3J9DQpzYW1wbGUuZGYgPC0gcmVhZC5kZWxpbShwYXN0ZTAoREFUQV9ESVIsICJHVEV4X0FuYWx5c2lzX3Y4X0Fubm90YXRpb25zX1NhbXBsZUF0dHJpYnV0ZXNEUy50eHQiKSwgYXMuaXMgPSBUUlVFLCBoZWFkZXIgPSBUUlVFLCByb3cubmFtZXMgPSAxKQ0Kc3ViamVjdC5kZiA8LSByZWFkLmRlbGltKHBhc3RlMChEQVRBX0RJUiwgIkdURXhfQW5hbHlzaXNfdjhfQW5ub3RhdGlvbnNfU3ViamVjdFBoZW5vdHlwZXNEUy50eHQiKSwgYXMuaXMgPSBUUlVFLCBoZWFkZXIgPSBUUlVFLCByb3cubmFtZXMgPSAxKQ0KYGBgDQoNClRoZSBgRFRISFJEWWAgY29sdW1uIHJlZmVycyB0byB0aGUgNC1wb2ludCBIYXJkeSBzY2FsZTogaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wcm9qZWN0cy9nYXAvY2dpLWJpbi92YXJpYWJsZS5jZ2k/c3R1ZHlfaWQ9cGhzMDAwNDI0LnY0LnAxJnBodj0xNjkwOTINCg0KUmVmZXIgdG8gdGhlIG1ldGFkYXRhIGZpbGVzIGhlcmUgZm9yIG1vcmUgaW5mb3JtYXRpb246IGh0dHBzOi8vZ3RleHBvcnRhbC5vcmcvaG9tZS9kb3dubG9hZHMvYWR1bHQtZ3RleC9tZXRhZGF0YQ0KDQpgYGB7cn0NCnN1YmplY3QuZGYNCmBgYA0KUmVmZXIgdG8gdGhlIG1ldGFkYXRhIGZpbGVzIGhlcmUgZm9yIG1vcmUgaW5mb3JtYXRpb246IGh0dHBzOi8vZ3RleHBvcnRhbC5vcmcvaG9tZS9kb3dubG9hZHMvYWR1bHQtZ3RleC9tZXRhZGF0YQ0KDQpgYGB7cn0NCnNhbXBsZS5kZg0KYGBgDQoNCkV4dHJhY3QgZW50cmllcyB0aGF0IHBlcnRhaW4gdG8gdHJhbnNjcmlwdG9taWMgKFJOQSkgZGF0YS4NCg0KYGBge3J9DQpybmFzZXEuc2FtcGxlLmRmIDwtIHNhbXBsZS5kZltzYW1wbGUuZGZbIlNNQUZSWkUiXSA9PSAiUk5BU0VRIiwgXQ0Kcm5hc2VxLnNhbXBsZS5kZg0KYGBgDQoNCiMjIElJSS4gRmlsdGVyaW5nIGNvbG9uIHNhbXBsZXMNCg0KVGhlIGBTTVRTRGAgY29sdW1uIHJlZmVycyB0byB0aGUgdGlzc3VlIHR5cGUgKGkuZS4sIHRoZSBhcmVhIGZyb20gd2hpY2ggdGhlIHNhbXBsZSB3YXMgdGFrZW4pLg0KDQpgYGB7cn0NCmFzLm1hdHJpeChzb3J0KHRhYmxlKHJuYXNlcS5zYW1wbGUuZGZbIlNNVFNEIl0pLCBkZWNyZWFzaW5nID0gVFJVRSkpDQpgYGANCldlIGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gdGhvc2UgZnJvbSB0aGUgY29sb3JlY3RhbCBhcmVhLg0KDQpgYGB7cn0NCmNvbG9uLnNhbXBsZS5kZiA8LSBybmFzZXEuc2FtcGxlLmRmICU+JSBkcGx5cjo6ZmlsdGVyKFNNVFNEID09ICJDb2xvbiAtIFNpZ21vaWQiKQ0KY29sb24uc2FtcGxlLmRmDQpgYGANCg0KIyMgSVYuIExvYWRpbmcgVFBNIGRhdGEgZnJvbSBHVEV4DQoNCmBHVEV4X0FuYWx5c2lzXzIwMTctMDYtMDVfdjhfUk5BU2VRQ3YxLjEuOV9nZW5lX3RwbS5nY3RgIGNvbnRhaW5zIHRoZSBnZW5lIFRQTXMuDQoNCmBgYHtyfQ0KdHBtLmRmIDwtIHJlYWQuZGVsaW0ocGFzdGUwKERBVEFfRElSLCAiR1RFeF9BbmFseXNpc18yMDE3LTA2LTA1X3Y4X1JOQVNlUUN2MS4xLjlfZ2VuZV90cG0uZ2N0IiksDQogIGFzLmlzID0gVCwgcm93Lm5hbWVzID0gMSwgY2hlY2submFtZXMgPSBGQUxTRSwgc2tpcCA9IDINCikNCmdlbmUubmFtZXMuZGYgPC0gdHBtLmRmWywgIkRlc2NyaXB0aW9uIiwgZHJvcCA9IEZBTFNFXQ0KdHBtLmRmIDwtIHRwbS5kZlssICEobmFtZXModHBtLmRmKSAlaW4lIGMoIkRlc2NyaXB0aW9uIikpXQ0Kew0KICBjYXQocGFzdGUoIk51bWJlciBvZiBnZW5lcyBpbiB0YWJsZTogIiwgZGltKHRwbS5kZilbMV0pKQ0KfQ0KYGBgDQpQZXJmb3JtIHNvbWUgZGF0YSBwcmVwcm9jZXNzaW5nLg0KDQpgYGB7cn0NCiMgUmVtb3ZlIHZlcnNpb24gbnVtYmVyOiBodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvZ3JleC92ZXJzaW9ucy8xLjkvdG9waWNzL2NsZWFuaWQNCnRwbS5kZiRlbnNlbWJsIDwtIGNsZWFuaWQocm93bmFtZXModHBtLmRmKSkNCmhlYWQodHBtLmRmJGVuc2VtYmwpDQpgYGANCkZBREQgaXMgb25lIG9mIHRoZSBrZXkgZ2VuZXMgaW52b2x2ZWQgaW4gbmVjcm9wdG9zaXMuDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBuYW1lZCB2ZWN0b3IgdG8gbWFwIG5hbWVzIHRvIElEcw0KbmFtZV90b19pZCA8LSBzZXROYW1lcyhyb3duYW1lcyhnZW5lLm5hbWVzLmRmKSwgZ2VuZS5uYW1lcy5kZiREZXNjcmlwdGlvbikNCg0KIyBDcmVhdGUgYSBuYW1lZCB2ZWN0b3IgdG8gbWFwIElEcyB0byBuYW1lcw0KaWRfdG9fbmFtZSA8LSBzZXROYW1lcyhnZW5lLm5hbWVzLmRmJERlc2NyaXB0aW9uLCByb3duYW1lcyhnZW5lLm5hbWVzLmRmKSkNCg0KIyBUbyByZXRyaWV2ZSB0aGUgSUQgZm9yICdGQUREJw0KcHJpbnQobmFtZV90b19pZFtbIkZBREQiXV0pDQpwcmludChpZF90b19uYW1lW1siRU5TRzAwMDAwMTY4MDQwLjQiXV0pDQpgYGANCg0KIyMgVi4gTG9hZGluZyBSQ0QgZ2VuZSBzZXRzDQoNCiMjIyBOZWNyb3B0b3Npcw0KDQpXZSBvYnRhaW4gdGhlIGdlbmUgc2V0IGZyb20gdGhlIEh1bWFuIE1TaWdEQiBDb2xsZWN0aW9uczogIA0KDQotIGBHT0JQX05FQ1JPUFRPVElDX1NJR05BTElOR19QQVRIV0FZYCByZWZlcnMgdG8gdGhlIG5lY3JvcHRvc2lzIGdlbmUgc2V0IChmb3VuZCB2aWEgTVNpZ0RCJ3Mgc2VhcmNoIGZ1bmN0aW9uYWxpdHk6IGh0dHBzOi8vd3d3LmdzZWEtbXNpZ2RiLm9yZy9nc2VhL21zaWdkYi9odW1hbi9zZWFyY2guanNwKS4gIA0KLSBUaGUgY2F0ZWdvcnkgYW5kIHN1YmNhdGVnb3J5IHBhcmFtZXRlcnMgd2VyZSBkZWNpZGVkIGJhc2VkIG9uIHRoaXMgZ2VuZSBzZXQuICANCi0gYEM1YCBjb25zaXN0cyBvZiBnZW5lcyBhbm5vdGF0ZWQgYnkgdGhlIHNhbWUgb250b2xvZ3kgdGVybSAoaHR0cHM6Ly93d3cuZ3NlYS1tc2lnZGIub3JnL2dzZWEvbXNpZ2RiLykuICANCi0gYEdPOkJQYCByZWZlcnMgdG8gdGhlICJiaW9sb2dpY2FsIHByb2Nlc3MiIGNhdGVnb3J5IGluIEdlbmUgT250b2xvZ3kuDQoNCkNBVkVBVCEgYEdPQlBfTkVDUk9QVE9USUNfU0lHTkFMSU5HX1BBVEhXQVlgIGNvbnRhaW5zIG9ubHkgOCBnZW5lcy4NCg0KYGBge3J9DQpuZWNyb3B0b3Npcy5nZW5lcyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiaHVtYW4iLCBjYXRlZ29yeSA9ICJDNSIsIHN1YmNhdGVnb3J5ID0gIkdPOkJQIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoZ3NfbmFtZSA9PSAiR09CUF9ORUNST1BUT1RJQ19TSUdOQUxJTkdfUEFUSFdBWSIpDQpuZWNyb3B0b3Npcy5nZW5lcw0KYGBgDQoNCiMjIyBGZXJyb3B0b3Npcw0KIA0KV2Ugb2J0YWluIHRoZSBnZW5lIHNldCBmcm9tIHRoZSBIdW1hbiBNU2lnREIgQ29sbGVjdGlvbnM6DQoNCi0gYFdQX0ZFUlJPUFRPU0lTYCByZWZlcnMgdG8gdGhlIGZlcnJvcHRvc2lzIGdlbmUgc2V0IChmb3VuZCB2aWEgTVNpZ0RCJ3Mgc2VhcmNoIGZ1bmN0aW9uYWxpdHk6IGh0dHBzOi8vd3d3LmdzZWEtbXNpZ2RiLm9yZy9nc2VhL21zaWdkYi9odW1hbi9zZWFyY2guanNwKS4NCi0gVGhlIGNhdGVnb3J5IGFuZCBzdWJjYXRlZ29yeSBwYXJhbWV0ZXJzIHdlcmUgZGVjaWRlZCBiYXNlZCBvbiB0aGlzIGdlbmUgc2V0LiAgIA0KLSBgQzJgIGNvbnNpc3RzIG9mIHRoZSBjdXJhdGVkIGdlbmUgc2V0cyAoaHR0cHM6Ly93d3cuZ3NlYS1tc2lnZGIub3JnL2dzZWEvbXNpZ2RiLykuICANCi0gYENQOldJS0lQQVRIV0FZU2AgcmVmZXJzIHRvIHRoZSBjdXJhdGVkIGdlbmUgc2V0IGZyb20gV2lraVBhdGh3YXlzLg0KDQpOb3RlIHRoYXQgdGhlcmUgaXMgYW5vdGhlciBmZXJyb3B0b3NpcyBnZW5lIHNldDogYEdPQlBfRkVSUk9QVE9TSVNgLiA8YnI+DQpIb3dldmVyLCBpdCBjb250YWlucyBvbmx5IDEwIGdlbmVzIChmb3IgY29tcGFyaXNvbiwgYFdQX0ZFUlJPUFRPU0lTYCBjb250YWlucyA2NCBnZW5lcykuDQoNCmBgYHtyfQ0KZmVycm9wdG9zaXMuZ2VuZXMgPC0gbXNpZ2RicihzcGVjaWVzID0gImh1bWFuIiwgY2F0ZWdvcnkgPSAiQzIiLCBzdWJjYXRlZ29yeSA9ICJDUDpXSUtJUEFUSFdBWVMiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihnc19uYW1lID09ICJXUF9GRVJST1BUT1NJUyIpDQpmZXJyb3B0b3Npcy5nZW5lcw0KYGBgDQoNCiMjIyBQeXJvcHRvc2lzDQoNCldlIG9idGFpbiB0aGUgZ2VuZSBzZXQgZnJvbSB0aGUgSHVtYW4gTVNpZ0RCIENvbGxlY3Rpb25zOg0KDQotIGBSRUFDVE9NRV9QWVJPUFRPU0lTYCByZWZlcnMgdG8gdGhlIHB5cm9wdG9zaXMgZ2VuZSBzZXQgKGZvdW5kIHZpYSBNU2lnREIncyBzZWFyY2ggZnVuY3Rpb25hbGl0eTogaHR0cHM6Ly93d3cuZ3NlYS1tc2lnZGIub3JnL2dzZWEvbXNpZ2RiL2h1bWFuL3NlYXJjaC5qc3ApLg0KLSBUaGUgY2F0ZWdvcnkgYW5kIHN1YmNhdGVnb3J5IHBhcmFtZXRlcnMgd2VyZSBkZWNpZGVkIGJhc2VkIG9uIHRoaXMgZ2VuZSBzZXQuDQotIGBDMmAgY29uc2lzdHMgb2YgdGhlIGN1cmF0ZWQgZ2VuZSBzZXRzIChodHRwczovL3d3dy5nc2VhLW1zaWdkYi5vcmcvZ3NlYS9tc2lnZGIvKS4NCi0gYENQOlJFQUNUT01FYCByZWZlcnMgdG8gdGhlIGN1cmF0ZWQgZ2VuZSBzZXQgZnJvbSBSZWFjdG9tZS4NCg0KYFJFQUNUT01FX1BZUk9QVE9TSVNgIGNvbnRhaW5zIDI3IGdlbmVzLg0KDQpgYGB7cn0NCnB5cm9wdG9zaXMuZ2VuZXMgPC0gbXNpZ2RicihzcGVjaWVzID0gImh1bWFuIiwgY2F0ZWdvcnkgPSAiQzIiLCBzdWJjYXRlZ29yeSA9ICJDUDpSRUFDVE9NRSIpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGdzX25hbWUgPT0gIlJFQUNUT01FX1BZUk9QVE9TSVMiKQ0KcHlyb3B0b3Npcy5nZW5lcw0KYGBgDQoNCiMjIFZJLiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzDQoNClNlbGVjdCBvbmx5IHRoZSB0aXNzdWUgc2FtcGxlcyAoY29sdW1ucykgZnJvbSB0aGUgY29sb3JlY3RhbCBhcmVhLg0KDQpgYGB7cn0NCnRwbS5jb2xvbi5kZiA8LSB0cG0uZGYgJT4lIGRwbHlyOjpzZWxlY3QoYyhlbnNlbWJsLCByb3duYW1lcyhjb2xvbi5zYW1wbGUuZGYpKSkNCnRwbS5jb2xvbi5kZg0KYGBgDQoNCiMjIyBOZWNyb3B0b3Npcw0KDQpHZXQgdGhlIFRQTSBmb3IgdGhlIGdlbmVzIGluIHRoZSBuZWNyb3B0b3NpcyBnZW5lIHNldC4NCg0KYGBge3J9DQp0cG0uY29sb24ubmVjcm8uZGYgPC0gdHBtLmNvbG9uLmRmICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmwgJWluJSBuZWNyb3B0b3Npcy5nZW5lcyRlbnNlbWJsX2dlbmUpDQp0cG0uY29sb24ubmVjcm8uZGYyIDwtIGxlZnRfam9pbih0cG0uY29sb24ubmVjcm8uZGYsIG5lY3JvcHRvc2lzLmdlbmVzICU+JSBkcGx5cjo6c2VsZWN0KGVuc2VtYmxfZ2VuZSwgZ2VuZV9zeW1ib2wpLCBieSA9IGMoImVuc2VtYmwiID0gImVuc2VtYmxfZ2VuZSIpKQ0KdHBtLmNvbG9uLm5lY3JvLmRmJGdlbmVfc3ltYm9sIDwtIHRwbS5jb2xvbi5uZWNyby5kZjIkZ2VuZV9zeW1ib2wNCnRwbS5jb2xvbi5uZWNyby5kZg0KYGBgDQoNCkNvbXB1dGUgdGhlIG1lZGlhbiBUUE0gcGVyIGdlbmUuDQoNCmBgYHtyfQ0KZ2VuZS5leHByZXNzaW9ucy5uZWNybyA8LSBkYXRhLmZyYW1lKA0KICByb3cubmFtZXMgPSB0cG0uY29sb24ubmVjcm8uZGYkZ2VuZV9zeW1ib2wsDQogIHRpc3N1ZSA9ICJDb2xvbiIsDQogIHRwbSA9IG1hdHJpeFN0YXRzOjpyb3dNZWRpYW5zKGFzLm1hdHJpeCh0cG0uY29sb24ubmVjcm8uZGYgJT4lIGRwbHlyOjpzZWxlY3QoLWMoImVuc2VtYmwiLCAiZ2VuZV9zeW1ib2wiKSkpKQ0KKQ0KZ2VuZS5leHByZXNzaW9ucy5uZWNybw0KYGBgDQoNClBsb3QgdGhlIGdlbmUgZXhwcmVzc2lvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoZ2VuZS5leHByZXNzaW9ucy5uZWNybywgYWVzKHkgPSB0aXNzdWUsIHggPSByb3duYW1lcyhnZW5lLmV4cHJlc3Npb25zLm5lY3JvKSwgZmlsbCA9IHRwbSkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgaGp1c3QgPSAxKQ0KICApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJFeHByZXNzaW9uIG9mIG5lY3JvcHRvc2lzLXJlbGF0ZWQgZ2VuZXMgaW4gR1RFeCBjb2xvbiB0aXNzdWVzIiwNCiAgICB4ID0gIkdlbmUiLA0KICAgIHkgPSAiQXJlYSIsDQogICAgZmlsbCA9ICJUUE0iDQogICkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdHBtKSwgdmp1c3QgPSAxKQ0KYGBgDQoqKlF1aWNrIHZhbGlkYXRpb246KiogUklQSzEgYW5kIG5lY3JvcHRvc2lzIC0gaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zMTIyNzYtMDIyLTAwODQ3LTQNCg0KIyMjIEZlcnJvcHRvc2lzDQoNCkdldCB0aGUgVFBNIGZvciB0aGUgZ2VuZXMgaW4gdGhlIGZlcnJvcHRvc2lzIGdlbmUgc2V0Lg0KDQpgYGB7cn0NCnRwbS5jb2xvbi5mZXJyby5kZiA8LSB0cG0uY29sb24uZGYgJT4lIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibCAlaW4lIGZlcnJvcHRvc2lzLmdlbmVzJGVuc2VtYmxfZ2VuZSkNCnRwbS5jb2xvbi5mZXJyby5kZjIgPC0gbGVmdF9qb2luKHRwbS5jb2xvbi5mZXJyby5kZiwgZmVycm9wdG9zaXMuZ2VuZXMgJT4lIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lLCBnZW5lX3N5bWJvbCksIGJ5ID0gYygiZW5zZW1ibCIgPSAiZW5zZW1ibF9nZW5lIikpDQp0cG0uY29sb24uZmVycm8uZGYkZ2VuZV9zeW1ib2wgPC0gdHBtLmNvbG9uLmZlcnJvLmRmMiRnZW5lX3N5bWJvbA0KdHBtLmNvbG9uLmZlcnJvLmRmDQpgYGANCkNvbXB1dGUgdGhlIG1lZGlhbiBUUE0gcGVyIGdlbmUuDQoNCmBgYHtyfQ0KZ2VuZS5leHByZXNzaW9ucy5mZXJybyA8LSBkYXRhLmZyYW1lKA0KICByb3cubmFtZXMgPSB0cG0uY29sb24uZmVycm8uZGYkZ2VuZV9zeW1ib2wsDQogIHRpc3N1ZSA9ICJDb2xvbiIsDQogIHRwbSA9IG1hdHJpeFN0YXRzOjpyb3dNZWRpYW5zKGFzLm1hdHJpeCh0cG0uY29sb24uZmVycm8uZGYgJT4lIGRwbHlyOjpzZWxlY3QoLWMoImVuc2VtYmwiLCAiZ2VuZV9zeW1ib2wiKSkpKQ0KKQ0KZ2VuZS5leHByZXNzaW9ucy5mZXJybw0KYGBgDQpQbG90IHRoZSBnZW5lIGV4cHJlc3Npb24uDQoNCmBgYHtyfQ0KZ2dwbG90KGdlbmUuZXhwcmVzc2lvbnMuZmVycm8sIGFlcyh5ID0gdGlzc3VlLCB4ID0gcm93bmFtZXMoZ2VuZS5leHByZXNzaW9ucy5mZXJybyksIGZpbGwgPSB0cG0pKSArDQogIGdlb21fdGlsZSgpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gInJlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRXhwcmVzc2lvbiBvZiBmZXJyb3B0b3Npcy1yZWxhdGVkIGdlbmVzIGluIEdURXggY29sb24gdGlzc3VlcyIsDQogICAgeCA9ICJHZW5lIiwNCiAgICB5ID0gIkFyZWEiLA0KICAgIGZpbGwgPSAiVFBNIg0KICApDQpgYGANCioqUXVpY2sgdmFsaWRhdGlvbjoqKiBGVEgxIGFuZCBmZXJyb3B0b3NpcyAtIGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNDIwLTAyMi0wMDkwMi16DQoNCiMjIyBQeXJvcHRvc2lzDQoNCkdldCB0aGUgVFBNIGZvciB0aGUgZ2VuZXMgaW4gdGhlIHB5cm9wdG9zaXMgZ2VuZSBzZXQuDQoNCmBgYHtyfQ0KdHBtLmNvbG9uLnB5cm8uZGYgPC0gdHBtLmNvbG9uLmRmICU+JSBkcGx5cjo6ZmlsdGVyKGVuc2VtYmwgJWluJSBweXJvcHRvc2lzLmdlbmVzJGVuc2VtYmxfZ2VuZSkNCnRwbS5jb2xvbi5weXJvLmRmMiA8LSBsZWZ0X2pvaW4odHBtLmNvbG9uLnB5cm8uZGYsIHB5cm9wdG9zaXMuZ2VuZXMgJT4lIGRwbHlyOjpzZWxlY3QoZW5zZW1ibF9nZW5lLCBnZW5lX3N5bWJvbCksIGJ5ID0gYygiZW5zZW1ibCIgPSAiZW5zZW1ibF9nZW5lIikpDQp0cG0uY29sb24ucHlyby5kZiRnZW5lX3N5bWJvbCA8LSB0cG0uY29sb24ucHlyby5kZjIkZ2VuZV9zeW1ib2wNCnRwbS5jb2xvbi5weXJvLmRmDQpgYGANCg0KQ29tcHV0ZSB0aGUgbWVkaWFuIFRQTSBwZXIgZ2VuZS4NCg0KYGBge3J9DQpnZW5lLmV4cHJlc3Npb25zLnB5cm8gPC0gZGF0YS5mcmFtZSgNCiAgcm93Lm5hbWVzID0gdHBtLmNvbG9uLnB5cm8uZGYkZ2VuZV9zeW1ib2wsDQogIHRpc3N1ZSA9ICJDb2xvbiIsDQogIHRwbSA9IG1hdHJpeFN0YXRzOjpyb3dNZWRpYW5zKGFzLm1hdHJpeCh0cG0uY29sb24ucHlyby5kZiAlPiUgZHBseXI6OnNlbGVjdCgtYygiZW5zZW1ibCIsICJnZW5lX3N5bWJvbCIpKSkpDQopDQpnZW5lLmV4cHJlc3Npb25zLnB5cm8NCmBgYA0KDQpQbG90IHRoZSBnZW5lIGV4cHJlc3Npb24uDQoNCmBgYHtyfQ0KZ2dwbG90KGdlbmUuZXhwcmVzc2lvbnMucHlybywgYWVzKHkgPSB0aXNzdWUsIHggPSByb3duYW1lcyhnZW5lLmV4cHJlc3Npb25zLnB5cm8pLCBmaWxsID0gdHBtKSkgKw0KICBnZW9tX3RpbGUoKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBhbmdsZSA9IDkwLCBoanVzdCA9IDEpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkV4cHJlc3Npb24gb2YgcHlyb3B0b3Npcy1yZWxhdGVkIGdlbmVzIGluIEdURXggY29sb24gdGlzc3VlcyIsDQogICAgeCA9ICJHZW5lIiwNCiAgICB5ID0gIkFyZWEiLA0KICAgIGZpbGwgPSAiVFBNIg0KICApDQpgYGANCioqUXVpY2sgdmFsaWRhdGlvbjoqKiBDSE1QNEIgYW5kIHB5cm9wdG9zaXMgLSBodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzM4ODIzMDAwLw==